package com.item.util;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.util.StreamUtils;

import com.base.CoreConstants;
import com.base.exception.SystemException;
import com.base.mobile.MErrorEnum;
import com.base.mobile.MobException;
import com.base.mobile.MobileInfo;
import com.base.mobile.server.annotation.Mobile;
import com.base.mobile.server.annotation.MobileMethod;
import com.base.util.SpringContextUtil;
import com.google.gson.Gson;

public class MobileJsonServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private Logger logger = Logger.getLogger(MobileJsonServlet.class);

	//保存接口方法注解
	private Map<String, MobileMethod> mobileMethodAnnoMap = new HashMap<String, MobileMethod>();
	//保存接口方法
	private Map<String, Method> mobileMethodMap = new HashMap<String, Method>();

	public void init() throws ServletException {
		try {
			// 获取所有的手机接口类
			Map mobileClz = SpringContextUtil.getBeansWithAnnotation(Mobile.class);
			if (mobileClz != null) {
				//遍历所有接口类
				for (Iterator localIterator = mobileClz.values().iterator(); localIterator.hasNext();) {
					Object clzObj = localIterator.next();
					//获取类所有接口方法
					List<Method> methodList = ClassUtils.getClassMethodByAnnotation(clzObj.getClass(), MobileMethod.class);

					//遍历所有接口方法
					for (Method method : methodList) {
						MobileMethod methodAnno = (MobileMethod) method.getAnnotation(MobileMethod.class);
						
						String methodName = methodAnno.methodno();
						if (StringUtils.isBlank(methodName)) {
							continue;
						}
						
						if (this.mobileMethodAnnoMap.containsKey(methodName)) {
							throw new SystemException("手机接口:" + methodName + "有重复定义,请检查代码!");
						}
						this.mobileMethodMap.put(methodName, method);
						this.mobileMethodAnnoMap.put(methodName, methodAnno);
					}
				}
			}
		} catch (Exception e) {
			this.logger.error(e.getMessage(), e);
			throw new ServletException(e.getMessage(), e);
		}
	}

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	    Object requestMethodResult = null;
	    ServletOutputStream sos;
	    Map jsonShow = new HashMap();;
	    
//	    Enumeration ee = req.getHeaderNames();
//	  	while(ee.hasMoreElements()) {
//	  		String name = ee.nextElement().toString();
//	  		System.out.println(name + ":" + req.getHeader(name));
//	    }

		try {
			//获取请求参数
			Map paramMap = getParam(req);
			String methodName = (String)paramMap.get("methodno");
			paramMap.remove("methodno");
		    paramMap.remove("debug");
		    
		    MobileMethod mobileMethod = (MobileMethod)this.mobileMethodAnnoMap.get(methodName);
			if (mobileMethod == null) {
				throw new SystemException("请求的接口:" + methodName + "在服务器端没有定义,请检查!");
			}
			
			String hasAppId = CoreConstants.getProperty("mobile.hasAppId");
			
			if ("true".equals(hasAppId) && StringUtils.isBlank((String) paramMap.get("appid"))) {
				throw new SystemException(MErrorEnum.APPID_FAIL_ERROR);
			}
			
			if (StringUtils.isBlank((String) paramMap.get("deviceid"))) {
				throw new SystemException(MErrorEnum.DEVICE_FAIL_ERROR);
			}
			
			//登录验证
			if (mobileMethod.isLogin()){
				if (StringUtils.isBlank((String) paramMap.get("userid"))) {
					throw new SystemException(MErrorEnum.LOGIN_FAIL_ERROR);
				}

				if (StringUtils.isBlank((String) paramMap.get("verify"))) {
					throw new SystemException(MErrorEnum.LOGIN_FAIL_ERROR);
				}
				
				String verifyMethod = CoreConstants.getProperty("mobile.verifyMethod");
				if (StringUtils.isBlank(verifyMethod)) {
					throw new SystemException("未配置手机登录校验方法(mobile.verifyMethod),传入参数为appid,userid,verify,deviceid");
				}
				
				String[] verifyMethodArray = verifyMethod.split("\\.");

		        if (verifyMethodArray.length != 2) {
		          throw new SystemException("手机登录校验方法(mobile.verifyMethod)格式不对,格式为:类名.方法名");
		        }
		        
		        Map params = new HashMap();
		        params.put("appid", paramMap.get("appid"));
		        params.put("userid", paramMap.get("userid"));
		        params.put("verify", paramMap.get("verify"));
		        params.put("deviceid", paramMap.get("deviceid"));
		        
				boolean isVerify = ((Boolean)ClassUtils.invokeMethod(verifyMethodArray[0], verifyMethodArray[1], params)).booleanValue();
				if (!isVerify) {
					throw new SystemException(MErrorEnum.LOGIN_FAIL_ERROR);
				}
			}
			
			//是否分页
			if (mobileMethod.isPage()){
				if (StringUtils.isBlank((String) paramMap.get("page"))) {
					throw new SystemException(MErrorEnum.PAGE_PARAM1_ERROR);
				}
				if (StringUtils.isBlank((String) paramMap.get("limit"))) {
					throw new SystemException(MErrorEnum.PAGE_PARAM2_ERROR);
				}
			}
			
			
			//请求接口方法
			requestMethodResult = requestMethod(methodName, mobileMethod, paramMap);
			jsonShow.put("errorCode", 0);
			jsonShow.put("errorMsg", "");
		} catch (Exception e) {
			//异常处理
			Throwable rootThrowable = ExceptionUtils.getRootCause(e) == null ? e : ExceptionUtils.getRootCause(e);
			this.logger.error(rootThrowable.getMessage(), rootThrowable);
			jsonShow.put("errorCode", 0);
			if ((rootThrowable instanceof MobException)) {
				Integer errorCode = ((MobException) rootThrowable).getCode();
				jsonShow.put("errorCode",errorCode == null ? 10000 : errorCode.intValue());
			} else {
				jsonShow.put("errorCode", -1);
			}
			jsonShow.put("errorMsg",rootThrowable.getMessage() == null ? String.valueOf(rootThrowable) : rootThrowable.getMessage());
		}finally{
			sos = resp.getOutputStream();
			try {
				resp.setContentType("text/plain; charset=utf-8");
				resp.setCharacterEncoding("UTF-8");
				jsonShow.put("data", requestMethodResult);
//				sos.write(JSONUtils.serialize(jsonShow).getBytes("UTF-8"));
				sos.write(new Gson().toJson(jsonShow).getBytes("UTF-8"));
				sos.flush();
			} catch (Exception e) {
				this.logger.error(e.getMessage(), e);
			} finally {
				if (sos != null){
					sos.close();
				}
			}
	    }
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
	
	public void destroy() {
		this.mobileMethodMap.clear();
		this.mobileMethodAnnoMap.clear();
	}

	private Map<String, Object> getParam(HttpServletRequest request) throws Exception {
		Map paramMap = new HashMap();
		String methodName = null;
		for (Object paramName : request.getParameterMap().keySet()) {
			if (!StringUtils.isNotBlank((String) paramName)){
				continue;
			}
			String paramValue = request.getParameter((String) paramName);

			if ("methodno".equals(paramName)) {
				methodName = paramValue;
			}
			paramMap.put(paramName, paramValue);
		}
		
		String str = new String(StreamUtils.copyToByteArray(request.getInputStream()),request.getCharacterEncoding());
		if(StringUtils.isNotBlank(str)){
			for(String temp : str.split("&")){
				String[] nameValue = temp.split("=");
				paramMap.put(nameValue[0], URLDecoder.decode((String)nameValue[1],request.getCharacterEncoding()));
			}
		}
//		System.out.println((HashMap<String, String>)paramMap);
//		byte[] protobuf = StreamUtils.copyToByteArray(request.getInputStream());
//
//		MRequest.Msg_Request.Builder requestProtobuf = (MRequest.Msg_Request.Builder) ProtobufUtils.deserialize(
//				new DES().desDecrypt(protobuf), MRequest.Msg_Request.class);
//
//		for (int i = 0; i < requestProtobuf.getPostsCount(); i++) {
//			System.out.println(requestProtobuf.getPosts(i).getName());
//			paramMap.put(requestProtobuf.getPosts(i).getName(), requestProtobuf.getPosts(i).getValue());
//		}
//
//		if ((requestProtobuf.getRequestMessage() != null) && (requestProtobuf.getRequestMessage().size() > 0)) {
//			MobileMethod mobileMethod = (MobileMethod) this.mobileMethodAnnoMap.get(methodName);
//
//			if (mobileMethod != null) {
//				Class requestClz = mobileMethod.reqClz();
//
//				paramMap.put("requestProto", ProtobufUtils.deserialize(requestProtobuf.getRequestMessage(), requestClz));
//			}
//
//		}
		MobileInfo mobileInfo = new MobileInfo((String) paramMap.get("userid"), (String) paramMap.get("deviceid"),
				(String) paramMap.get("verify"));
		paramMap.put("mobileInfo", mobileInfo);
		return paramMap;
	}
	
	private Object requestMethod(String methodName, MobileMethod mobileMethod, Map<String, Object> paramMap)
			throws Exception {
		Method method = (Method) this.mobileMethodMap.get(methodName);
		Object methodResult = ClassUtils.invokeMethod(method.getDeclaringClass().getSimpleName(), method.getName(), paramMap);
		return methodResult;
	}
}
